#include "../../config.h"

#include "version.h"

namespace gpyp {
namespace conf {

//========================
// Version
std::vector<uint> Version::parse(const Glib::ustring &str) {
  std::vector<uint> res;
  for(const char *c = str.c_str(); c && *c;) {
    for( ; *c && (*c < '0' || *c > '9'); ++c) ;
    if (!*c) {
      break;
    }
    char *end = NULL;
    long t = strtol(c, &end, 10);
    res.push_back(t);
    c = end;
  }
  std::vector<uint>::iterator iter = res.begin(), eiter = res.end();
  for( ; iter != res.end(); ++iter) {
    if (*iter != 0) {
      eiter = iter + 1;
    }
  }
  res.erase(eiter, res.end());
  return res;
}

const Glib::ustring &Version::get() const {
  return str_;
}
const std::vector<uint> &Version::get_terms() const {
  return terms_;
}
void Version::set(const Version &version) {
  str_   = version.str_;
  terms_ = version.terms_;
}
void Version::set(const Glib::ustring &version) {
  str_   = version;
  terms_ = parse(version);
}

#define FOREACH_VERSION_OPERATORS(M, T, V)      \
  M(T, ==, V) M(T, !=, V) M(T, <, V)            \
  M(T, <=, V) M(T, >, V) M(T, >=, V)

#define IMPL_VERSION_CMP_OPERATOR(T, C, V)              \
  bool Version::operator C(const T &version) const {    \
    return terms_ C V.terms_;                           \
  }
#define IMPL_VERSION_OPERATORS(T, V)                            \
  const T &Version::operator=(const T &version) {               \
    set(version);                                               \
    return version;                                             \
  }                                                             \
  FOREACH_VERSION_OPERATORS(IMPL_VERSION_CMP_OPERATOR, T, V)

IMPL_VERSION_OPERATORS(Version, version)
IMPL_VERSION_OPERATORS(Glib::ustring, Version(version))

Version::Version() {
  set(version_current);
}
Version::Version(const Version &version) {
  set(version);
}
Version::Version(const Glib::ustring &version) {
  set(version);
}

//========================
std::ostream &operator<<(std::ostream &os, const Version &v) {
  os << v.get();
  return os;
}

//========================
Version version_current(PACKAGE_VERSION);

//========================
// RefAttributeVersion
#define IMPL_REFVERSION_CMP_OPERATOR(T, C, V)                           \
  bool RefAttributeVersion::operator C(const T &version) const {        \
    return RefAttribute<AttributeVersion>::get()->get_value() C V;      \
  }
#define IMPL_REFVERSION_OPERATORS(T, V)                         \
  const T &RefAttributeVersion::operator=(const T &version) {   \
    RefAttribute<AttributeVersion>::get()->set_value(version);  \
    return version;                                             \
  }                                                             \
  FOREACH_VERSION_OPERATORS(IMPL_REFVERSION_CMP_OPERATOR, T, V)

IMPL_REFVERSION_OPERATORS(Version, version)
IMPL_REFVERSION_OPERATORS(Glib::ustring, Version(version))

RefAttributeVersion::RefAttributeVersion(const Glib::ustring &name,
                                         const Version &def) :
  RefAttribute<AttributeVersion>(name, def)
{
}

}/*conf*/
}/*gpyp*/
